
angular.module('ngPlugin',[])
    .constant('tinymceConfig',{
        onChange: function(e) {
            // put logic here for keypress and cut/paste changes
        },
        inline: false,
        skin: 'lightgray',
        height : 300,
        width:410,
        menubar: false,
        language: 'zh_CN',
        // handle_event_callback: 'eventHandle',
        plugins: [
            "advlist autolink lists link image  charmap print preview hr anchor pagebreak",
            "searchreplace wordcount visualblocks visualchars code fullscreen",
            "insertdatetime media nonbreaking save table contextmenu directionality",
            "emoticons template paste textcolor"
        ],
        // 'undo redo  | styleselect | bold underline italic | link  alignleft aligncenter alignright alignjustify | fontselect fontsizeselect'
        toolbar: [
            'undo redo  | styleselect | bold italic | link  alignleft aligncenter alignright alignjustify | fontselect | fontsizeselect'
        ],
    })
    .directive('ngDatetimepicker', function () {
        return {
            restrict: 'AC',
            scope: {
                config: '=?',
                ngModel: '='
            },
            link: function (scope, ele, attr) {
                ele.datetimepicker({
                    format:'YYYY-MM-DD HH:mm:ss',// format:'HH:mm',
                    locale:'zh-cn',
                    icons: {
                        time: "fa fa-clock-o",
                        date: "fa fa-calendar",
                        up: "fa fa-chevron-up",
                        down: "fa fa-chevron-down",
                        previous: 'fa fa-chevron-left',
                        next: 'fa fa-chevron-right',
                        today: 'fa fa-screenshot',
                        clear: 'fa fa-trash',
                        close: 'fa fa-remove'
                    }
                }).on('dp.change', function (e) {
                    // console.log(e.date);
                    scope.ngModel = new moment(e.date).format('YYYY-MM-DD HH:mm:ss');
                    scope.$apply();
                });
            }
        }
    })
    //后期重写
    .provider('notify',function(){
        var notifyEle;
        return {
            $get: ['$timeout', '$compile', '$rootScope', function ($timeout, $compile, $rootScope) {
                var colortypes = ['','info','success','warning','danger'];
                return function(message,type,from,align){
                    from = from || 'top';
                    align = align || 'center';
                    type = type || 0;
                    if(notifyEle){
                        notifyEle.close();
                    }
                    notifyEle = $.notify({
                        message: message
                    },{
                        element:$('body', parent.document).length>0?$('body', parent.document)[0]:'body',
                        position:'fixed',
                        type: colortypes[type],
                        timer: 1000,
                        placement: {
                            from: from,
                            align: align
                        }
                    });
                    return notifyEle;
                }
            }]
        }
    })
    //后期重写
    .directive('ngFileInput', function (notify) {
        return {
            restrict: 'AC',
            scope: {
                fileConfig: '=?',
                ngModel: '=',
                refresh: '='
            },
            require: 'ngModel',
            link: function (scope, ele, attr,ctrl) {
                scope._token = ele.closest('form').find('input[name="_token"]').val();
                function getFileName(fileUrl){
                    return fileUrl.substring(fileUrl.lastIndexOf('/')+1,fileUrl.lastIndexOf("."));
                }
                ctrl.$formatters.unshift(function (modelValue) {
                    if(scope.refresh){
                        refresh();
                    }
                });
                var defaultOptions ={
                    language: 'zh',
                    // deleteUrl:'',
                    overwriteInitial:true,
                    uploadUrl: '/web/prize/upload',
                    resizeImage: true,
                    // maxFileSize: config.maxFileSize,
                    // maxImageWidth: config.maxImageWidth,
                    // maxImageHeight: config.maxImageHeight,
                    // uploadAsync: true,
                    allowedPreviewTypes: ['image'],
                    initialPreviewShowDelete: true,
                    dropZoneEnabled: false,
                    showUploadedThumbs: true,
                    showCaption: true,
                    showPreview: true,
                    uploadExtraData: {"_token": scope._token},
                    allowedFileExtensions: ["csv", "gif", "png", "jpg"],
                    // elErrorContainer: "#fileError",
                    enctype: 'multipart/form-data',
                    browseClass: "btn btn-primary",
                    browseLabel: "选择...",
                    maxFileCount: 10,
                    showUpload: true,
                    showCancel: false,
                    showRemove: true,
                    // msgFilesTooMany: "选择上传的文件数量({n}) 超过允许的最大数值{m}！",
                    //uploadClass: "btn btn-info",
                    //uploadLabel: "部署",
                    //uploadIcon: '<i ></i>',
                }
                var events ={
                    'fileselect': function(event,numFiles,label,options){},
                    'filereset': function(){
                        scope.ngModel = '';
                        scope.refresh = false;
                        scope.$apply();
                    },
                    'fileuploaded': function(event,data,previewId,index,options){
                        if(data.response.code == 0){
                            scope.ngModel = data.response.result;
                            scope.refresh = false;
                            scope.$apply();
                        }else{
                            notify('图片上传失败',4);
                        }
                    },
                    'filecleared': function(event,options){
                        scope.ngModel = '';
                        scope.refresh = false;
                        scope.$apply();
                    },
                    'filesuccessremove': function(event,id,options){
                        // console.log(event,id,options);
                        scope.ngModel = '';
                        scope.refresh = false;
                        scope.$apply();
                    },
                    'filedeleted': function(event,key,options){
                        // console.log(event,key,options);
                        scope.ngModel = '';
                        scope.refresh = false;
                        scope.$apply();
                    },
                    'fileimageuploaded': function(event, data, msg){
                        // console.log(event, data, msg);
                    }
                }
                var options = angular.extend({},defaultOptions,scope.fileConfig.config);
                var events = angular.extend({},events,scope.fileConfig.events);
                scope.fileInput = ele.fileinput(options)
                    .on('fileselect',function(event,numFiles,label){
                        events.fileselect(event,numFiles,label,options);
                    }).on('fileuploaded', function (event, data, previewId, index) {
                        events.fileuploaded(event, data, previewId, index,options);
                    }).on('filecleared', function (event) {
                        events.filecleared(event,options);
                    }).on('filedeleted', function (event, key){
                        events.filedeleted(event,key,options);
                    }).on('filereset', function (event) {
                        events.filereset(event,options);
                    }).on('filesuccessremove', function (event, id) {
                        events.filesuccessremove(event,id,options);
                    });
                function refresh(){
                    if(scope.ngModel&&scope.refresh){
                        scope.fileObjs = [];
                        scope.initialPreviewConfig = [];
                        scope.fileObjs.push(scope.ngModel);
                        scope.initialPreviewConfig.push({key:getFileName(scope.ngModel.length>0?scope.ngModel:''),showDelete: false});
                        scope.fileInput = ele.fileinput('refresh',{
                            initialPreview: scope.fileObjs,
                            initialPreviewConfig:scope.initialPreviewConfig,
                            initialPreviewAsData: true,
                        });
                    }
                }
            }
        }
    })
        //后期重写
    .provider('eChart',function(){
        return {
            $get: ['$timeout', '$compile', '$rootScope', function ($timeout, $compile, $rootScope) {
                return function(dom,option){
                    var eChart = echarts.init(dom);
                    eChart.setOption(option);
                    return eChart;
                }
            }]
        }
    })
    //tinymce
    .value('uiTinymceConfig', {})
    .directive('uiTinymce', ['$rootScope', '$compile', '$timeout', '$window', '$sce', 'uiTinymceConfig', 'uiTinymceService', function($rootScope, $compile, $timeout, $window, $sce, uiTinymceConfig, uiTinymceService) {
        uiTinymceConfig = uiTinymceConfig || {};

        if (uiTinymceConfig.baseUrl) {
            tinymce.baseURL = uiTinymceConfig.baseUrl;
        }

        return {
            require: ['ngModel', '^?form'],
            priority: 599,
            link: function(scope, element, attrs, ctrls) {
                if (!$window.tinymce) {
                    return;
                }

                var ngModel = ctrls[0],
                    form = ctrls[1] || null;

                var expression, options = {
                        debounce: true
                    }, tinyInstance,
                    updateView = function(editor) {
                        var content = editor.getContent({format: options.format}).trim();
                        content = $sce.trustAsHtml(content);

                        ngModel.$setViewValue(content);
                        if (!$rootScope.$$phase) {
                            scope.$digest();
                        }
                    };

                function toggleDisable(disabled) {
                    if (disabled) {
                        ensureInstance();

                        if (tinyInstance) {
                            tinyInstance.getBody().setAttribute('contenteditable', false);
                        }
                    } else {
                        ensureInstance();

                        if (tinyInstance && !tinyInstance.settings.readonly && tinyInstance.getDoc()) {
                            tinyInstance.getBody().setAttribute('contenteditable', true);
                        }
                    }
                }

                // fetch a unique ID from the service
                var uniqueId = uiTinymceService.getUniqueId();
                attrs.$set('id', uniqueId);

                expression = {};

                angular.extend(expression, scope.$eval(attrs.uiTinymce));

                //Debounce update and save action
                var debouncedUpdate = (function(debouncedUpdateDelay) {
                    var debouncedUpdateTimer;
                    return function(ed) {
                        $timeout.cancel(debouncedUpdateTimer);
                        debouncedUpdateTimer = $timeout(function() {
                            return (function(ed) {
                                if (ed.isDirty()) {
                                    ed.save();
                                    updateView(ed);
                                }
                            })(ed);
                        }, debouncedUpdateDelay);
                    };
                })(400);

                var setupOptions = {
                    // Update model when calling setContent
                    // (such as from the source editor popup)
                    setup: function(ed) {
                        ed.on('init', function() {
                            ngModel.$render();
                            ngModel.$setPristine();
                            ngModel.$setUntouched();
                            if (form) {
                                form.$setPristine();
                            }
                        });

                        // Update model when:
                        // - a button has been clicked [ExecCommand]
                        // - the editor content has been modified [change]
                        // - the node has changed [NodeChange]
                        // - an object has been resized (table, image) [ObjectResized]
                        ed.on('ExecCommand change NodeChange ObjectResized', function() {
                            if (!options.debounce) {
                                ed.save();
                                updateView(ed);
                                return;
                            }
                            debouncedUpdate(ed);
                        });

                        ed.on('blur', function() {
                            element[0].blur();
                            ngModel.$setTouched();
                            if (!$rootScope.$$phase) {
                                scope.$digest();
                            }
                        });

                        ed.on('remove', function() {
                            element.remove();
                        });

                        if (uiTinymceConfig.setup) {
                            uiTinymceConfig.setup(ed, {
                                updateView: updateView
                            });
                        }

                        if (expression.setup) {
                            expression.setup(ed, {
                                updateView: updateView
                            });
                        }
                    },
                    format: expression.format || 'html',
                    selector: '#' + attrs.id
                };
                // extend options with initial uiTinymceConfig and
                // options from directive attribute value
                angular.extend(options, uiTinymceConfig, expression, setupOptions);
                // Wrapped in $timeout due to $tinymce:refresh implementation, requires
                // element to be present in DOM before instantiating editor when
                // re-rendering directive
                $timeout(function() {
                    if (options.baseURL){
                        tinymce.baseURL = options.baseURL;
                    }
                    var maybeInitPromise = tinymce.init(options);
                    if(maybeInitPromise && typeof maybeInitPromise.then === 'function') {
                        maybeInitPromise.then(function() {
                            toggleDisable(scope.$eval(attrs.ngDisabled));
                        });
                    } else {
                        toggleDisable(scope.$eval(attrs.ngDisabled));
                    }
                });

                ngModel.$formatters.unshift(function(modelValue) {
                    return modelValue ? $sce.trustAsHtml(modelValue) : '';
                });

                ngModel.$parsers.unshift(function(viewValue) {
                    return viewValue ? $sce.getTrustedHtml(viewValue) : '';
                });

                ngModel.$render = function() {
                    ensureInstance();

                    var viewValue = ngModel.$viewValue ?
                        $sce.getTrustedHtml(ngModel.$viewValue) : '';

                    // instance.getDoc() check is a guard against null value
                    // when destruction & recreation of instances happen
                    if (tinyInstance &&
                        tinyInstance.getDoc()
                    ) {
                        tinyInstance.setContent(viewValue);
                        // Triggering change event due to TinyMCE not firing event &
                        // becoming out of sync for change callbacks
                        tinyInstance.fire('change');
                    }
                };

                attrs.$observe('disabled', toggleDisable);

                // This block is because of TinyMCE not playing well with removal and
                // recreation of instances, requiring instances to have different
                // selectors in order to render new instances properly
                var unbindEventListener = scope.$on('$tinymce:refresh', function(e, id) {
                    var eid = attrs.id;
                    if (angular.isUndefined(id) || id === eid) {
                        var parentElement = element.parent();
                        var clonedElement = element.clone();
                        clonedElement.removeAttr('id');
                        clonedElement.removeAttr('style');
                        clonedElement.removeAttr('aria-hidden');
                        tinymce.execCommand('mceRemoveEditor', false, eid);
                        parentElement.append($compile(clonedElement)(scope));
                        unbindEventListener();
                    }
                });

                scope.$on('$destroy', function() {
                    ensureInstance();

                    if (tinyInstance) {
                        tinyInstance.remove();
                        tinyInstance = null;
                    }
                });

                function ensureInstance() {
                    if (!tinyInstance) {
                        tinyInstance = tinymce.get(attrs.id);
                    }
                }
            }
        };
    }])
    .service('uiTinymceService', [
        /**
         * A service is used to create unique ID's, this prevents duplicate ID's if there are multiple editors on screen.
         */
            function() {
            var UITinymceService = function() {
                var ID_ATTR = 'ui-tinymce';
                // uniqueId keeps track of the latest assigned ID
                var uniqueId = 0;
                // getUniqueId returns a unique ID
                var getUniqueId = function() {
                    uniqueId ++;
                    return ID_ATTR + '-' + uniqueId;
                };
                // return the function as a public method of the service
                return {
                    getUniqueId: getUniqueId
                };
            };
            // return a new instance of the service
            return new UITinymceService();
        }
    ])
    .factory('$modalStack', ['$animate', '$timeout', '$document', '$compile', '$rootScope', '$$stackedMap',
        function ($animate, $timeout, $document, $compile, $rootScope, $$stackedMap) {

            var OPENED_MODAL_CLASS = 'modal-open';

            var backdropDomEl, backdropScope;
            var openedWindows = $$stackedMap.createNew();
            var $modalStack = {};

            function backdropIndex() {
                var topBackdropIndex = -1;
                var opened = openedWindows.keys();
                for (var i = 0; i < opened.length; i++) {
                    if (openedWindows.get(opened[i]).value.backdrop) {
                        topBackdropIndex = i;
                    }
                }
                return topBackdropIndex;
            }

            $rootScope.$watch(backdropIndex, function (newBackdropIndex) {
                if (backdropScope) {
                    backdropScope.index = newBackdropIndex;
                }
            });

            function removeModalWindow(modalInstance) {

                var body = $document.find('body').eq(0);
                var modalWindow = openedWindows.get(modalInstance).value;

                //clean up the stack
                openedWindows.remove(modalInstance);

                //remove window DOM element
                removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, function () {
                    body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
                    checkRemoveBackdrop();
                });
            }

            function checkRemoveBackdrop() {
                //remove backdrop if no longer needed
                if (backdropDomEl && backdropIndex() == -1) {
                    var backdropScopeRef = backdropScope;
                    removeAfterAnimate(backdropDomEl, backdropScope, function () {
                        backdropScopeRef = null;
                    });
                    backdropDomEl = undefined;
                    backdropScope = undefined;
                }
            }

            function removeAfterAnimate(domEl, scope, done) {
                // Closing animation
                scope.animate = false;

                if (domEl.attr('modal-animation') && $animate.enabled()) {
                    // transition out
                    domEl.one('$animate:close', function closeFn() {
                        $rootScope.$evalAsync(afterAnimating);
                    });
                } else {
                    // Ensure this call is async
                    $timeout(afterAnimating);
                }

                function afterAnimating() {
                    if (afterAnimating.done) {
                        return;
                    }
                    afterAnimating.done = true;

                    domEl.remove();
                    scope.$destroy();
                    if (done) {
                        done();
                    }
                }
            }

            $document.bind('keydown', function (evt) {
                var modal;

                if (evt.which === 27) {
                    modal = openedWindows.top();
                    if (modal && modal.value.keyboard) {
                        evt.preventDefault();
                        $rootScope.$apply(function () {
                            $modalStack.dismiss(modal.key, 'escape key press');
                        });
                    }
                }
            });

            $modalStack.open = function (modalInstance, modal) {

                var modalOpener = $document[0].activeElement;

                openedWindows.add(modalInstance, {
                    deferred: modal.deferred,
                    renderDeferred: modal.renderDeferred,
                    modalScope: modal.scope,
                    backdrop: modal.backdrop,
                    keyboard: modal.keyboard
                });

                var body = $document.find('body').eq(0),
                    currBackdropIndex = backdropIndex();

                if (currBackdropIndex >= 0 && !backdropDomEl) {
                    backdropScope = $rootScope.$new(true);
                    backdropScope.index = currBackdropIndex;
                    var angularBackgroundDomEl = angular.element('<div modal-backdrop="modal-backdrop"></div>');
                    angularBackgroundDomEl.attr('backdrop-class', modal.backdropClass);
                    if (modal.animation) {
                        angularBackgroundDomEl.attr('modal-animation', 'true');
                    }
                    backdropDomEl = $compile(angularBackgroundDomEl)(backdropScope);
                    body.append(backdropDomEl);
                }

                var angularDomEl = angular.element('<div modal-window="modal-window"></div>');
                angularDomEl.attr({
                    'template-url': modal.windowTemplateUrl,
                    'window-class': modal.windowClass,
                    'size': modal.size,
                    'index': openedWindows.length() - 1,
                    'animate': 'animate'
                }).html(modal.content);
                if (modal.animation) {
                    angularDomEl.attr('modal-animation', 'true');
                }

                var modalDomEl = $compile(angularDomEl)(modal.scope);
                openedWindows.top().value.modalDomEl = modalDomEl;
                openedWindows.top().value.modalOpener = modalOpener;
                body.append(modalDomEl);
                body.addClass(OPENED_MODAL_CLASS);
            };

            function broadcastClosing(modalWindow, resultOrReason, closing) {
                return !modalWindow.value.modalScope.$broadcast('modal.closing', resultOrReason, closing).defaultPrevented;
            }

            $modalStack.close = function (modalInstance, result) {
                var modalWindow = openedWindows.get(modalInstance);
                if (modalWindow && broadcastClosing(modalWindow, result, true)) {
                    modalWindow.value.deferred.resolve(result);
                    removeModalWindow(modalInstance);
                    modalWindow.value.modalOpener.focus();
                    return true;
                }
                return !modalWindow;
            };

            $modalStack.dismiss = function (modalInstance, reason) {
                var modalWindow = openedWindows.get(modalInstance);
                if (modalWindow && broadcastClosing(modalWindow, reason, false)) {
                    modalWindow.value.deferred.reject(reason);
                    removeModalWindow(modalInstance);
                    modalWindow.value.modalOpener.focus();
                    return true;
                }
                return !modalWindow;
            };

            $modalStack.dismissAll = function (reason) {
                var topModal = this.getTop();
                while (topModal && this.dismiss(topModal.key, reason)) {
                    topModal = this.getTop();
                }
            };

            $modalStack.getTop = function () {
                return openedWindows.top();
            };

            $modalStack.modalRendered = function (modalInstance) {
                var modalWindow = openedWindows.get(modalInstance);
                if (modalWindow) {
                    modalWindow.value.renderDeferred.resolve();
                }
            };

            return $modalStack;
        }])
    .provider('$modal', function () {

        var $modalProvider = {
            options: {
                animation: true,
                backdrop: true, //can also be false or 'static'
                keyboard: true
            },
            $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack',
                function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {

                    var $modal = {};

                    function getTemplatePromise(options) {
                        return options.template ? $q.when(options.template) :
                            $http.get(angular.isFunction(options.templateUrl) ? (options.templateUrl)() : options.templateUrl,
                                {cache: $templateCache}).then(function (result) {
                                return result.data;
                            });
                    }

                    function getResolvePromises(resolves) {
                        var promisesArr = [];
                        angular.forEach(resolves, function (value) {
                            if (angular.isFunction(value) || angular.isArray(value)) {
                                promisesArr.push($q.when($injector.invoke(value)));
                            }
                        });
                        return promisesArr;
                    }

                    $modal.open = function (modalOptions) {

                        var modalResultDeferred = $q.defer();
                        var modalOpenedDeferred = $q.defer();
                        var modalRenderDeferred = $q.defer();

                        //prepare an instance of a modal to be injected into controllers and returned to a caller
                        var modalInstance = {
                            result: modalResultDeferred.promise,
                            opened: modalOpenedDeferred.promise,
                            rendered: modalRenderDeferred.promise,
                            close: function (result) {
                                return $modalStack.close(modalInstance, result);
                            },
                            dismiss: function (reason) {
                                return $modalStack.dismiss(modalInstance, reason);
                            }
                        };

                        //merge and clean up options
                        modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
                        modalOptions.resolve = modalOptions.resolve || {};

                        //verify options
                        if (!modalOptions.template && !modalOptions.templateUrl) {
                            throw new Error('One of template or templateUrl options is required.');
                        }

                        var templateAndResolvePromise =
                            $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));


                        templateAndResolvePromise.then(function resolveSuccess(tplAndVars) {

                            var modalScope = (modalOptions.scope || $rootScope).$new();
                            modalScope.$close = modalInstance.close;
                            modalScope.$dismiss = modalInstance.dismiss;

                            var ctrlInstance, ctrlLocals = {};
                            var resolveIter = 1;

                            //controllers
                            if (modalOptions.controller) {
                                ctrlLocals.$scope = modalScope;
                                ctrlLocals.$modalInstance = modalInstance;
                                angular.forEach(modalOptions.resolve, function (value, key) {
                                    ctrlLocals[key] = tplAndVars[resolveIter++];
                                });

                                ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
                                if (modalOptions.controllerAs) {
                                    modalScope[modalOptions.controllerAs] = ctrlInstance;
                                }
                            }

                            $modalStack.open(modalInstance, {
                                scope: modalScope,
                                deferred: modalResultDeferred,
                                renderDeferred: modalRenderDeferred,
                                content: tplAndVars[0],
                                animation: modalOptions.animation,
                                backdrop: modalOptions.backdrop,
                                keyboard: modalOptions.keyboard,
                                backdropClass: modalOptions.backdropClass,
                                windowClass: modalOptions.windowClass,
                                windowTemplateUrl: modalOptions.windowTemplateUrl,
                                size: modalOptions.size
                            });

                        }, function resolveError(reason) {
                            modalResultDeferred.reject(reason);
                        });

                        templateAndResolvePromise.then(function () {
                            modalOpenedDeferred.resolve(true);
                        }, function (reason) {
                            modalOpenedDeferred.reject(reason);
                        });

                        return modalInstance;
                    };

                    return $modal;
                }]
        };

        return $modalProvider;
    })
    .factory('$$stackedMap', function () {
        return {
            createNew: function () {
                var stack = [];

                return {
                    add: function (key, value) {
                        stack.push({
                            key: key,
                            value: value
                        });
                    },
                    get: function (key) {
                        for (var i = 0; i < stack.length; i++) {
                            if (key == stack[i].key) {
                                return stack[i];
                            }
                        }
                    },
                    keys: function () {
                        var keys = [];
                        for (var i = 0; i < stack.length; i++) {
                            keys.push(stack[i].key);
                        }
                        return keys;
                    },
                    top: function () {
                        return stack[stack.length - 1];
                    },
                    remove: function (key) {
                        var idx = -1;
                        for (var i = 0; i < stack.length; i++) {
                            if (key == stack[i].key) {
                                idx = i;
                                break;
                            }
                        }
                        return stack.splice(idx, 1)[0];
                    },
                    removeTop: function () {
                        return stack.splice(stack.length - 1, 1)[0];
                    },
                    length: function () {
                        return stack.length;
                    }
                };
            }
        };
    })
    .factory('ngModal',['$modal',function($modal) {
        function modalResult(options) {
            var modalInstance = $modal.open({
                templateUrl : options.templateUrl,
                controller: options.controller,
                resolve: options.resolve
            });
            modalInstance.rendered.then(function(){
                if(angular.isFunction(options.rendered)){
                    options.rendered();
                }
            });
            modalInstance.result.then(function(selectedItem) {
                options.ok(selectedItem);
                angular.element('.dialog_content .grid').getNiceScroll().resize();
            }, function() {
                options.cancel();
                angular.element('.dialog_content .grid').getNiceScroll().resize();
            });
        }
        return modalResult;
    }])
    .directive('modalBackdrop', ['$timeout', function ($timeout) {
        return {
            restrict: 'EA',
            replace: true,
            templateUrl: '/components/backdrop.html',
            compile: function (tElement, tAttrs) {
                tElement.addClass(tAttrs.backdropClass);
                return linkFn;
            }
        };

        function linkFn(scope, element, attrs) {
            scope.animate = false;

            //trigger CSS transitions
            $timeout(function () {
                scope.animate = true;
            });
        }
    }])
    .directive('modalWindow', ['$modalStack', '$q', function ($modalStack, $q) {
        return {
            restrict: 'EA',
            scope: {
                index: '@',
                animate: '='
            },
            replace: true,
            transclude: true,
            templateUrl: function(tElement, tAttrs) {
                return tAttrs.templateUrl || '/components/window.html';
            },
            link: function (scope, element, attrs) {
                element.addClass(attrs.windowClass || '');
                scope.size = attrs.size;

                scope.close = function (evt) {
                    var modal = $modalStack.getTop();
                    if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) {
                        evt.preventDefault();
                        evt.stopPropagation();
                        $modalStack.dismiss(modal.key, 'backdrop click');
                    }
                };

                // This property is only added to the scope for the purpose of detecting when this directive is rendered.
                // We can detect that by using this property in the template associated with this directive and then use
                // {@link Attribute#$observe} on it. For more details please see {@link TableColumnResize}.
                scope.$isRendered = true;

                // Deferred object that will be resolved when this modal is render.
                var modalRenderDeferObj = $q.defer();
                // Observe function will be called on next digest cycle after compilation, ensuring that the DOM is ready.
                // In order to use this way of finding whether DOM is ready, we need to observe a scope property used in modal's template.
                attrs.$observe('modalRender', function (value) {
                    if (value == 'true') {
                        modalRenderDeferObj.resolve();
                    }
                });

                modalRenderDeferObj.promise.then(function () {
                    // trigger CSS transitions
                    scope.animate = true;

                    var inputsWithAutofocus = element[0].querySelectorAll('[autofocus]');
                    /**
                     * Auto-focusing of a freshly-opened modal element causes any child elements
                     * with the autofocus attribute to lose focus. This is an issue on touch
                     * based devices which will show and then hide the onscreen keyboard.
                     * Attempts to refocus the autofocus element via JavaScript will not reopen
                     * the onscreen keyboard. Fixed by updated the focusing logic to only autofocus
                     * the modal element if the modal does not contain an autofocus element.
                     */
                    if (inputsWithAutofocus.length) {
                        inputsWithAutofocus[0].focus();
                    } else {
                        element[0].focus();
                    }

                    // Notify {@link $modalStack} that modal is rendered.
                    var modal = $modalStack.getTop();
                    if (modal) {
                        $modalStack.modalRendered(modal.key);
                    }
                });
            }
        };
    }])
    .directive('modalAnimationClass', [
        function () {
            return {
                compile: function (tElement, tAttrs) {
                    if (tAttrs.modalAnimation) {
                        tElement.addClass(tAttrs.modalAnimationClass);
                    }
                }
            };
        }])
    .directive('modalTransclude', function () {
        return {
            link: function($scope, $element, $attrs, controller, $transclude) {
                $transclude($scope.$parent, function(clone) {
                    $element.empty();
                    $element.append(clone);
                });
            }
        };
    })
    .directive('ngDropdown', function ($timeout) {
        return {
            restrict: 'AC',
            require: 'ngModel',
            scope: {
                n: '=n',
                width: '=width',
                model: '=ngModel',
                disabled: '@disabled',
                options: '=options',
                label: '@label',
                value: '@value',
                isEmptylabel: '@',
                emptylabel: '@emptylabel'
            },
            replace: true,
            template: '<div class="dropdown"><div class="selected"><em></em><i class="fa fa-angle-down fa-lg"></i></div><ul></ul></div>',
            link: function (scope, ele, attr, ctrl) {
                if (!ctrl) return {};
                var height = (scope.n * 30) + 'px',$ul=ele.find('ul'),$em=ele.find('em'),$flag=false;
                $ul.height(height).hide();
                function render(){
                    $ul.empty();
                    var html = '';
                    if(Array.isArray(scope.options)){
                        if(typeof(scope.options[0]) == "object"){
                            if(scope.label&&scope.value){
                                $.each(scope.options,function(index,item){
                                    if(item[scope.value]==scope.model){
                                        html += '<li class="selected" value="'+item[scope.value]+'">'+item[scope.label]+'</li>';
                                    }else{
                                        html += '<li value="'+item[scope.value]+'">'+item[scope.label]+'</li>';
                                    }
                                });
                            }else{
                                $.each(scope.options,function(index,item){
                                    if(item.value==scope.model){
                                        html += '<li class="selected" value="'+item.value+'">'+item.name+'</li>';
                                    }else{
                                        html += '<li value="'+item.value+'">'+item.name+'</li>';
                                    }
                                });
                            }
                        }else{
                            $.each(scope.options,function(index,item){
                                if(item==scope.model){
                                    html += '<li class="selected" value="'+item+'">'+item+'</li>';
                                }else{
                                    html += '<li value="'+item+'">'+item+'</li>';
                                }
                            });
                        }
                    }else{
                        for(var key in scope.options){
                            if(key==scope.model){
                                html += '<li class="selected" value="'+key+'">'+scope.options[key]+'</li>';
                            }else{
                                html += '<li value="'+key+'">'+scope.options[key]+'</li>';
                            }
                        }
                    }
                    $ul.append(html).niceScroll({cursorborder: '',cursorcolor: '#000',cursoropacitymax: '0.5'});
                    if($ul.find('li.selected').length>0){
                        $em.html($ul.find('li.selected').html());
                    }else{
                        if(scope.isEmptylabel=='true'){
                            $ul.prepend('<li class="selected" value="">'+(scope.emptylabel?scope.emptylabel:'请选择')+'</li>');
                            $em.html(scope.emptylabel?scope.emptylabel:'请选择');
                        }else{
                            $em.html('');
                        }
                    }
                    $ul.find('li').hover(function(event){
                        $(this).addClass('hover').siblings('li').removeClass('hover');
                    });
                    $ul.find('li').off('click').on('click',function(e){
                        var $this = $(this);
                        $this.addClass('selected').siblings('li').removeClass('selected');
                        $em.html($this.html());
                        $flag = true;
                        scope.model = $this.attr('value');
                        scope.$apply();
                        $ul.hide();
                        $ul.getNiceScroll().resize();
                    });
                }
                if (!scope.disabled || scope.disabled == 'false') {
                    ele.hover(function () {
                        $(this).find('ul').show();
                        $('ul', ele).getNiceScroll().resize();
                    }, function () {
                        $(this).find('ul').hide();
                        $('ul', ele).getNiceScroll().resize();
                    });
                }else{
                    ele.addClass('disabled');
                }
                ctrl.$formatters.unshift(function (modelValue) {
                    if(!$flag){
                        $.each($ul.find('li'),function(index,item){
                            if($(item).attr('value')==modelValue){
                                $(item).addClass('selected').siblings('li').removeClass('selected');
                                $em.html($(item).html());
                            }else{
                                $ul.find('li').siblings('li').removeClass('selected');
                                $em.html('');
                            }
                        });
                    }
                    $flag = false;
                });
                scope.$watch('options', function () {
                    $timeout(render, 10);
                },true);
            }
        };
    })
    .directive('ngAddImage', function (notify) {
        return {
            restrict: 'ACEM',
            require: 'ngModel',
            scope: {
                src: '=ngModel',
                base64: '=',
                config: '=?'
            },
            replace: true,
            transclude: true,
            template: '<div class="fileUpload"><label for="upload_{{config.id}}">上传图片（不超过2MB）</label><input name="upfile" id="upload_{{config.id}}" type="file"/></div>',
            link: function (scope, ele, attr, ctrl) {
                var options = {
                    id: '001',
                    fileSize: 2*1024*1024
                }
                var opts = angular.extend({},options,scope.config);
                function getLocalImgBase64(src) {
                    var read = new FileReader();
                    read.onload = function(e) {
                        scope.base64 =  e.target.result;
                        scope.$apply();
                    }
                    read.readAsDataURL(src);
                }
                ele.find('input[type=file]').on('change',function(event){
                    var filePath = $(this).val(),fileSize;
                    if (!/.(gif|jpg|jpeg|png|bmp|GIF|JPG|JPEG|PNG|BMP)$/.test(filePath)) {
                        notify('上传图片格式错误，请重新上传!', 2);
                        $(this).val('');
                        return false;
                    }
                    var isIE = /msie/i.test(navigator.userAgent) && !window.opera;
                    if (isIE && !this.files) {
                        var fileSystem = new ActiveXObject('Scripting.FileSystemObject');
                        var file = fileSystem.GetFile(filePath);
                        fileSize = file.Size;
                    } else {
                        fileSize = this.files[0].size;
                    }
                    if(opts.fileSize && fileSize>parseInt(opts.fileSize)){
                        notify('上传图片大于2M，请重新上传!', 2);
                        $(this).val('');
                        return false;
                    }
                    scope.src = filePath;
                    getLocalImgBase64(this.files[0]);
                });
            }
        }
    })
    .directive('ngViewImage', function ($timeout, $compile) {
        var viewElement;
        return {
            scope: {},
            restrict: 'AC',
            link: function (scope, ele, attr) {
                scope.close = function(){
                    viewElement.find('.imageViewContent').removeClass('fadeIn');
                    viewElement.find('.cover').removeClass('fadeIn');
                    setTimeout(function(){
                        viewElement.remove();
                        viewElement = '';
                    },450);
                };
                ele.click(function(event){
                    if(viewElement){
                        scope.close();
                    }
                    var html = '<div class="imageView"><div class="cover" ng-click="close($event)"></div><div class="imageViewContent"><i class="fa fa-close fa-lg" ng-click="close($event)"></i><div class="imgWrap">'
                        +'<img src="'+attr.src+'" alt="'+attr.alt+'" title="'+attr.title+'"/></div></div></div>';
                    viewElement = $compile(html)(scope);
                    angular.element('body').append(viewElement);
                    setTimeout(function(){
                        viewElement.find('.imageViewContent').addClass('fadeIn');
                        viewElement.find('.cover').addClass('fadeIn');
                    },2);
                });
            }
        }
    })
    .directive('ngEchart',function(eChart,$timeout){
        return {
            scope: {
                // title: '@',
                // legendData: '@',
                data: '=',
                type: '@',
            },
            restrict: 'AC',
            link: function (scope, ele, attr) {
                var labelData = [],valueData=[];
                function refreshData(){
                    if(!scope.echart){
                        return;
                    }
                    labelData = [],valueData=[];
                    //更新数据
                    var option = scope.echart.getOption();
                    if(scope.type=='bar'){
                        for(var i=1;i<=scope.data.length;i++){
                            labelData.push('选项'+i);
                            valueData.push(scope.data[i-1].total);
                        }
                        option.xAxis.data = labelData;
                    }else if(scope.type=='pie'){
                        for(var i=1;i<=scope.data.length;i++){
                            labelData.push('选项'+i);
                            valueData.push({
                                value: scope.data[i-1].total,
                                name: '选项'+i
                            });
                        }
                        option.legend.data = labelData;
                    }
                    option.series[0].data = valueData;
                    scope.echart.clear();
                    scope.echart.setOption(option);
                }
                scope.$watch('data',function(){
                    refreshData();
                },true);
                if(scope.type=='bar'){
                    for(var i=1;i<=scope.data.length;i++){
                        labelData.push('选项'+i);
                        valueData.push(scope.data[i-1].total);
                    }
                   scope.echart = eChart(ele[0],{
                        tooltip: {},
                        legend: {
                            data: ['人次']
                        },
                        xAxis: {
                            data: labelData
                        },
                        yAxis: {},
                        series: [{
                            name: '人次',
                            type: 'bar',
                            barWidth: 34,
                            data: valueData
                        }]
                    });
                }else if(scope.type=='pie'){
                    for(var i=1;i<=scope.data.length;i++){
                        labelData.push('选项'+i);
                        valueData.push({
                            value: scope.data[i-1].total,
                            name: '选项'+i
                        });
                    }
                    scope.echart = eChart(ele[0], {
                        tooltip: {
                            trigger: 'item',
                            formatter: "{a} <br/>{b}: {c} ({d}%)"
                        },
                        legend: {
                            orient: 'vertical',
                            x: 'left',
                            data: labelData
                        },
                        series: [
                            {
                                name: '访问来源',
                                type: 'pie',
                                radius: ['50%', '70%'],
                                avoidLabelOverlap: false,
                                label: {
                                    normal: {
                                        show: false,
                                        position: 'center'
                                    },
                                    emphasis: {
                                        show: true,
                                        textStyle: {
                                            fontSize: '30',
                                            fontWeight: 'bold'
                                        }
                                    }
                                },
                                labelLine: {
                                    normal: {
                                        show: false
                                    }
                                },
                                data: valueData
                            }
                        ]
                    });
                }
            }
        }
    })
    .directive('ngBGeocoder', function ($timeout,notify) {
        return {
            restrict: 'AC',
            replace: true,
            scope: {
                mapaddress: '=mapaddress',
                longitude: '=longitude',
                latitude: '=latitude',
                autocomplateid: '@autocomplateid',
                index: '@index',
            },
            template: '<div class="mapContainer"></div>',
            link: function (scope, ele, attrs) {
                var defaultPosition = {
                    position: [104.072343, 30.663538],
                    address: '四川省成都市青羊区西御河街道天府广场',
                    zoom: 17
                };
                angular.forEach(angular.element('.mapContainer'), function (item, index) {
                    angular.element(item).attr('id', 'BMap' + index);
                });
                var map = new BMap.Map('BMap' + scope.index,{enableMapClick:false});
                var dPoint = new BMap.Point(defaultPosition.position[0], defaultPosition.position[1]);
                map.centerAndZoom(dPoint, defaultPosition.zoom);
                map.setCurrentCity("成都");
                map.disableScrollWheelZoom(true);
                map.setDefaultCursor("pointer");

                // map.addControl(new BMap.MapTypeControl());
                // map.addControl(new BMap.MapTypeControl({mapTypes: [BMAP_NORMAL_MAP,BMAP_SATELLITE_MAP ]}));
                map.addControl(new BMap.ScaleControl({anchor: BMAP_ANCHOR_BOTTOM_LEFT}));
                map.addControl(new BMap.NavigationControl());
                map.addControl(new BMap.OverviewMapControl());

                function autocomplete(){
                    if(scope.autocomplateid){
                        var ac = new BMap.Autocomplete({
                            "input" : scope.autocomplateid,
                            "location" : map,
                            "autoFill": true
                        });
                        var myValue = scope.mapaddress?scope.mapaddress:'';
                        ac.addEventListener("onconfirm", function(e) {    //鼠标点击下拉列表后的事件
                            var _value = e.item.value;
                            myValue = _value.province +  _value.city +  _value.district +  _value.street +  _value.business;
                            scope.mapaddress = myValue;
                            scope.$apply();
                            // G("searchResultPanel").innerHTML ="onconfirm<br />index = " + e.item.index + "<br />myValue = " + myValue;
                            setPlace();
                        });
                        function setPlace(){
                            map.clearOverlays();    //清除地图上所有覆盖物
                            function onSearchComplete(){
                                var pp = local.getResults().getPoi(0).point;    //获取第一个智能搜索的结果
                                scope.longitude = pp.lng;
                                scope.latitude = pp.lat;
                                scope.$apply();
                                map.centerAndZoom(pp, 17);
                                map.addOverlay(new BMap.Marker(pp));    //添加标注
                            }
                            var local = new BMap.LocalSearch(map, { //智能搜索
                                onSearchComplete: onSearchComplete
                            });
                            local.search(myValue);
                        }
                        ac.setInputValue(scope.mapaddress?scope.mapaddress:'');
                    }
                }
                autocomplete();
                var marker = new BMap.Marker(dPoint);
                map.addOverlay(marker);
                var geocoder = new BMap.Geocoder(), countflag = 0, infoWindow;

                map.addEventListener('click', function (e) {
                    geocoder.getLocation(e.point, function (rs) {
                        scope.mapaddress = rs.address;
                        scope.$apply();
                        map.clearOverlays();
                        marker = addMarker(e.point);
                    });
                });
                if (scope.longitude && scope.latitude) {
                    var point = new BMap.Point(scope.longitude, scope.latitude);
                    geocoder.getLocation(point, function (rs) {
                        map.clearOverlays();
                        marker = addMarker(point);
                    });
                } else if (scope.mapaddress) {
                    getPosition(scope.mapaddress);
                }

                function getPosition(address) {
                    geocoder.getPoint(address, function (pt) {
                        if (pt) {
                            marker = addMarker(pt);
                            // addInfoWindow(marker, address, pt);
                        } else {
                            notify("请添加坐标信息，您选择地址没有解析到结果!",4);
                        }
                    });
                }

                function addMarker(point) {
                    scope.longitude = point.lng;
                    scope.latitude = point.lat;
                    scope.$apply();
                    map.clearOverlays();
                    map.panTo(point);
                    // map.centerAndZoom(point, 15);
                    marker = new BMap.Marker(point);
                    map.addOverlay(marker);
                    return marker;
                }

                function addInfoWindow(marker, address, point) {
                    var opts = {
                        width: 200,
                        height: 30,
                        title: '逆解析地址：'
                    }
                    infoWindow = new BMap.InfoWindow(address, opts);
                    marker.addEventListener("mouseover", function () {
                        map.openInfoWindow(infoWindow, point);
                    });
                }
            }
        }
    })
    .directive('ngNiceScroll',function(){
        return {
            restrict: 'AC',
            replace: true,
            scope: {
                array: '='
            },
            link: function (scope, ele, attrs) {
                ele.niceScroll({cursorborder:'',cursorcolor:'#000',cursoropacitymax:'0.5'});
                scope.$watch('array',function(){
                    ele.getNiceScroll().resize();
                });
            }
        }
    })
    .filter("parseHTML", function ($sce) {
        return function (text) {
            return $sce.trustAsHtml(text);
        }
    })
